from feed_forward.backpropagation_layer import BackpropagationLayer

__author__ = 'Douglas'


class Backpropagation:
    def __init__(self, network, training_set, learn_rate, momentum):
        self.error = 0.0
        self.learn_rate = learn_rate
        self.momentum = momentum
        self.network = network
        self.training_set = training_set

        self.layer_map = dict(iter([(layer, BackpropagationLayer(self, layer)) for layer in self.network.layers]))

    def calculate_error(self, ideal_pattern):
        # clear out all previous error data
        for layer in self.layer_map.values():
            layer.clear_error()

        for layer in reversed(self.network.layers):
            self.layer_map[layer].calculate_error(ideal_pattern if layer.is_output else None)

    def iteration(self):
        for row in self.training_set:
            self.network.compute_outputs(row.input_pattern)
            self.calculate_error(row.ideal_output)

        self.learn()

        self.error = self.network.calculate_error(self.training_set)

    def learn(self):
        for layer in self.network.layers:
            self.layer_map[layer].learn(self.learn_rate, self.momentum)